package com.xue.action.sys;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import com.xue.AppContext;
import com.xue.pojo.sys.PermissionGroup;
import com.xue.pojo.sys.SysUser;
import com.xue.service.sys.SysMenuService;

/**
 * api拦截器
 * 
 * @date 2017年3月9日 上午9:53:40
 * @author xuejianxinokok@163.com
 */
public class LoginInterceptor implements HandlerInterceptor {
	private static final Logger logger = LoggerFactory.getLogger(LoginInterceptor.class);
	public static final int HTTP_STATUS_401 = 401;// unauthorized 没有认证
	public static final int HTTP_STATUS_403 = 403;// forbidden 服务器拒绝访问

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		// 1.验证session信息
		boolean success = checkSession(request, response, handler);
		if (!success) {// 如果没有成功直接返回
			return false;
		}
		// 2.验证是否拥有权限
		boolean hasPermission = checkPermission(handler);
		if (!hasPermission) {
			response.setStatus(HTTP_STATUS_403);
			return false;
		}

		return true;
	}

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		// 在这里销毁用户信息
		//AppContext.removeSession();
	}

	/**
	 * 
	 * Description: 验证session用户信息是否合法 <br/>
	 * Date:2019年3月29日 上午9:44:14
	 * 
	 * @author xuejianxin
	 * @param request
	 * @param response
	 * @param handler
	 * @return
	 */
	protected boolean checkSession(HttpServletRequest request, HttpServletResponse response, Object handler) {
		HttpSession session = request.getSession();
		try {
			SysUser user = AppContext.getLoginUser();
			if (null == session || null == user) {
				logger.info("管理员没有登录401");
				response.setStatus(HTTP_STATUS_401);
				return false;
			}
			//AppContext.setSession(session);// 设置当前session
		} catch (Exception e) {
			logger.info("非管理员登录401");
			response.setStatus(HTTP_STATUS_401);
			return false;
		}
		return true;
	}

	// 缓存方法对应的menuid
	public static final Map<String, Set<String>> METHOD_MENU_MAP = new HashMap<>();

	/**
	 * 
	 * Description:判断是否拥有权限<br/>
	 * Date: 2018年1月24日 下午3:41:23 <br/>
	 * 
	 * @author xuejianxin
	 * @param handler
	 * @return
	 */
	private Boolean checkPermission(Object handler) {
		HandlerMethod hm = null;
		// 判断是否执行的是spring 方法
		if (handler instanceof org.springframework.web.method.HandlerMethod) {
			hm = (HandlerMethod) handler;
		} else {
			return true;
		}
		// 获取当前用户
		SysUser user = AppContext.getLoginUser();
		// 获取用户菜单集合
		Set<String> myMenuIds = user.getMenuIds();
		// 如果菜单集合不存在说明没有权限
		if (null == myMenuIds || myMenuIds.isEmpty()) {
			logger.warn("-----------user={} no  menus", user.getUserid());
			return false;
		}

		// 获取要执行的方法名
		String executeMethodName = hm.getMethod().toString();
		// 从解析过的缓存中获取要执行的方法对应的菜单id
		Set<String> menuIds = METHOD_MENU_MAP.get(executeMethodName);

		if (null == menuIds) {// 还没有解析过
			// 获取权限注解
			PermissionGroup pg = hm.getMethodAnnotation(PermissionGroup.class);
			if (null == pg) {// 如果权限组注解不存在,默认放过
				return true;
			}
			String[] links = pg.value();// 提取权限组
			if (null == links || links.length == 0) {// 注解存在,但是没有权限组 ,验证不通过
				return false;
			}
			// link解析成菜单id
			Set<String> tempMenuIdSet = new HashSet<>();
			METHOD_MENU_MAP.put(executeMethodName, tempMenuIdSet);
			for (String link : links) {
				Optional<String> mid = SysMenuService.getMenuByLink(link);
				if (mid.isPresent()) {
					tempMenuIdSet.add(mid.get());
				} else {
					logger.warn("-----------method={},link={} cant not find menu id", executeMethodName, link);
				}
			}
			menuIds = tempMenuIdSet;
		}

		boolean ok = false;
		for (String mid : menuIds) {
			ok = myMenuIds.contains(mid);
			if (ok) {// 只要找到一个就算验证通过
				break;
			}
		}
		if (!ok) {
			logger.warn("-----------user={} no rights execute method={}", user.getUserid(), executeMethodName);
		}
		return ok;
	}

}
